package com.hqd.jjvm.util;

import bsh.EvalError;
import bsh.Interpreter;
import com.hqd.jjvm.rtda.heap.JClass;
import com.hqd.jjvm.rtda.heap.classloader.JClassLoader;
import com.hqd.jjvm.rtda.obj.JObject;
import org.apache.commons.lang.StringUtils;

import java.io.IOException;

public class ClassUtil {

    public static boolean isArrayClass(String className) {
        if (className.startsWith("[")) {
            return true;
        }
        return false;
    }

    public static JObject getJClassObj(String descriptor, JClassLoader loader) {
        try {
            Class<?> clazz = getClassByDescriptor(descriptor);
            return loader.loadJClass(clazz.getName()).getJObject();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new RuntimeException("unknow class type");
    }

    /**
     * 获取类名
     *
     * @param className
     * @return
     */
    public static String getClassSimpleName(String className) {
        if (StringUtils.isBlank(className)) {
            return className;
        }
        if (className.endsWith(".class")) {
            className = className.substring(0, className.lastIndexOf("\\."));
        }
        return className.substring(className.lastIndexOf("\\." + 1));
    }

    /**
     * 获取包路径
     *
     * @param className
     * @return
     */
    public static String getPackagePath(String className) {
        if (StringUtils.isBlank(className)) {
            return className;
        }
        if (className.endsWith(".class")) {
            className = className.substring(0, className.lastIndexOf("\\."));
        }
        return className.replaceAll("\\.", "/");
    }

    public static boolean isPrimitive(Class<?> clazz) {
        if (clazz == null) {
            return false;
        }
        return clazz.isPrimitive();
    }

    public static boolean isPrimitive(JClass jc) {
        if (jc == null) {
            return false;
        }
        String className = jc.getClassName().replaceAll("/", "\\.");
        try {
            Class clazz = Class.forName(className);
            return clazz.isPrimitive();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断是否基本类型
     *
     * @param descriptor
     * @return
     */
    public static boolean isPrimitive(Character descriptor) {
        if ("IFJDBSCZ".contains(descriptor.toString()))
            return true;
        return false;
    }

    public static boolean isPrimitive(String descriptor) {
        Class<?> clazz = getClassByDescriptor(descriptor);
        return isPrimitive(clazz);
    }

    public static boolean isFloat(String descriptor) {
        Class<?> clazz = getClassByDescriptor(descriptor);
        return clazz == float.class;
    }

    public static boolean isLong(String descriptor) {
        Class<?> clazz = getClassByDescriptor(descriptor);
        return clazz == long.class;
    }

    public static boolean isDouble(String descriptor) {
        Class<?> clazz = getClassByDescriptor(descriptor);
        return clazz == double.class;
    }

    public static boolean isDword(String descriptor) {
        Class<?> clazz = getClassByDescriptor(descriptor);
        return (clazz == long.class || clazz == double.class);
    }

    public static Class<?> getClassByDescriptor(String descriptor) {
        if (StringUtils.isNotBlank(descriptor)) {
            char type = descriptor.charAt(0);
            switch (type) {
                case 'B':
                    return byte.class;
                case 'C':
                    return char.class;
                case 'D':
                    return double.class;
                case 'F':
                    return float.class;
                case 'I':
                    return int.class;
                case 'J':
                    return long.class;
                case 'S':
                    return short.class;
                case 'Z':
                    return boolean.class;
                case '[':
                    Class<?> clazz = getClassByDescriptor(descriptor.replaceAll("\\[", ""));
                    if (clazz == null) {
                        return null;
                    }
                    Interpreter in = new Interpreter();
                    int arrDimension = descriptor.lastIndexOf("[");
                    StringBuilder sb = new StringBuilder(clazz.getName());
                    for (int i = arrDimension; i >= 0; i--) {
                        sb.append("[]");
                    }
                    sb.append(".class");
                    try {
                        return (Class) in.eval(sb.toString());
                    } catch (EvalError evalError) {
                        return null;
                    }
                case 'L':
                    try {
                        return Class.forName(descriptor.replaceFirst("L", "").replaceAll("/", "\\.").replaceAll(";", ""));
                    } catch (ClassNotFoundException e) {
                        //   e.printStackTrace();
                        return null;
                    }
            }
        }
        return null;
    }
}
